﻿using System;
using System.CodeDom;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using com.susi.util;
#pragma warning disable 618

namespace com.susi.codedom {
    public static class CodeDOMExtensions {
        public static bool HasMember(this CodeTypeDeclaration type, string name)
        {
            return type.Members.Cast<CodeTypeMember>().FirstOrDefault(v => v.Name == name) != null;
        }

        public static CodeTypeMember GetMember(this CodeTypeDeclaration type, string name)
        {
            return type.Members.Cast<CodeTypeMember>().FirstOrDefault(v => v.Name == name);
        }
        

        public static CodeNamespace GetOrCreatCodeNamespace(this CodeCompileUnit CodeCompileUnit, string name)
        {
            var exist = CodeCompileUnit.Namespaces
                                       .Cast<CodeNamespace>()
                                       .FirstOrDefault(v => v.Name == name);
            if (exist != null) return exist;
            exist = new CodeNamespace(name);
            CodeCompileUnit.Namespaces.Add(exist);

            return exist;
        }
        
        public static CodeTypeDeclaration GetOrCreatCodeTypeDeclaration(this CodeNamespace CodeNamespace, string name)
        {
            var exist = CodeNamespace.Types
                                     .Cast<CodeTypeDeclaration>()
                                     .FirstOrDefault(v => v.Name == name);
            if (exist != null) return exist;
            exist = new CodeTypeDeclaration(name);
            CodeNamespace.Types.Add(exist);
            return exist ;
        }

        /// <summary>
        /// 尝试加入成员
        /// </summary>
        /// <param name="CodeTypeDeclaration">目标</param>
        /// <param name="mem">成员</param>
        /// <param name="onSkipExist">返回已存在的成员</param>
        /// <returns>永远返回CodeType自身</returns>
        public static CodeTypeDeclaration AddMember(this CodeTypeDeclaration CodeTypeDeclaration, CodeTypeMember mem,Action<CodeTypeMember> onSkipExist=null)
        {
            var exist = CodeTypeDeclaration.Members
                                           .Cast<CodeTypeMember>()
                                           .FirstOrDefault(v => v.Name == mem.Name);
            if (exist != null) {
                onSkipExist?.Invoke(exist);
                return CodeTypeDeclaration;
            }
            CodeTypeDeclaration.Members.Add(mem);
            return CodeTypeDeclaration;
        }
        
        /// <summary>
        /// 尝试加入成员
        /// </summary>
        /// <param name="CodeTypeDeclaration">目标</param>
        /// <param name="mem">成员</param>
        /// <param name="onSkipExist">返回已存在的成员</param>
        /// <returns>永远返回CodeType自身</returns>
        public static CodeTypeDeclaration AddMember(this CodeTypeDeclaration CodeTypeDeclaration, IEnumerable<CodeTypeMember> mem, Action<CodeTypeMember> onSkipExist =null)
        {
            foreach (var member in mem) {
                AddMember(CodeTypeDeclaration, member,onSkipExist);
            }

            return CodeTypeDeclaration;
        }

        public static bool TryAddMember(this CodeTypeDeclaration CodeTypeDeclaration, CodeTypeMember mem)
        {
            var exist = CodeTypeDeclaration.Members
                                           .Cast<CodeTypeMember>()
                                           .FirstOrDefault(v => v.Name == mem.Name);
            if (exist != null) {
                return false;
            }
            CodeTypeDeclaration.Members.Add(mem);
            return true;
        }

        public static CodeCompileUnit SelectTypeToUnit(this CodeTypeDeclaration codeTypeDeclaration, CodeNamespace codeNamespace)
        {
            var coduni = new CodeCompileUnit();
            var codsp  = CopyWithoutTypes(codeNamespace);
            codsp.Types.Add(codeTypeDeclaration);
            coduni.Namespaces.Add(codsp);
            return coduni;
        }

        public static CodeNamespace CopyWithoutTypes(this CodeNamespace codeNamespace)
        {
            var codsp = new CodeNamespace();
            codsp.Comments.AddRange(codeNamespace.Comments);
            codsp.Imports.AddRange(codeNamespace.Imports.Cast<CodeNamespaceImport>().ToArray());
            codsp.Name = codeNamespace.Name;
            foreach (DictionaryEntry entry in codeNamespace.UserData) {
                codsp.UserData.Add(entry.Key,entry.Value);
            }
            return codsp;
        }
    }
}